/*
    Copyright (C) 2011 Hugo Arregui, FuDePAN

    This file is part of the Biopp Library.

    Biopp is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Biopp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Biopp.  If not, see <http://www.gnu.org/licenses/>.

    This is a test file.
*/
#include <string>
#include <iostream>
#include <sstream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "biopp/biopp.h"

using namespace biopp;

TEST(GenericSequenceTest, PseudoNucSequenceLength)
{
    PseudoNucSequence ps;

    ASSERT_EQ(0, ps.length());
}

TEST(GenericSequenceTest, NucSequenceLength)
{
    NucSequence ps;

    ASSERT_EQ(0, ps.length());
}

TEST(GenericSequenceTest, PseudoNucSequenceTripletClassComparison)
{
    const std::string s = "CTA";
    PseudoNucSequence ps(s);

    ASSERT_EQ(typeid(PseudoTriplet::NucType), typeid(ps[0]));
}

TEST(GenericSequenceTest, NucSequenceTripletClassComparison)
{
    const std::string s = "CTA";
    NucSequence ns(s);

    ASSERT_EQ(typeid(Triplet::NucType), typeid(ns[0]));
}

TEST(GenericSequenceTest, PseudoNucSequenceClear)
{
    const std::string s = "CTA";
    PseudoNucSequence ps(s);
    ps.clear();

    ASSERT_EQ(0, ps.get_offset());
    ASSERT_EQ(0, ps.length());
}

TEST(GenericSequenceTest, NucSequenceClear)
{
    const std::string s = "CTA";
    NucSequence ns(s);
    ns.clear();

    ASSERT_EQ(0, ns.get_offset());
    ASSERT_EQ(0, ns.length());
}

TEST(GenericSequenceTest, PseudoNucSequenceString)
{
    const std::string s = "CTA";
    const std::string s2 = "AACTA";
    PseudoNucSequence ps(s);
    PseudoNucSequence ps2(s2);
    ps2.set_offset(1);

    ASSERT_EQ("CUA", ps.getString());
    ASSERT_EQ("ACUA", ps2.getString());
}

TEST(GenericSequenceTest, NucSequenceString)
{
    const std::string s = "CTA";
    const std::string s2 = "TTTCTA";
    NucSequence ns(s);
    NucSequence ns2(s2);
    ns2.set_offset(2);

    ASSERT_EQ("CUA", ns.getString());
    ASSERT_EQ("UCUA", ns2.getString());
}

TEST(GenericSequenceTest, NucSequenceAsignation)
{
    const std::string s = "CTA";
    NucSequence n(s);
    NucSequence n2 = n;

    ASSERT_EQ(n2.get_offset(), n.get_offset());
    ASSERT_EQ(n2.getString(), n.getString());
}

TEST(GenericSequenceTest, NucSequenceCopyCtor)
{
    const std::string s = "CTA";
    NucSequence n(s);
    NucSequence n2(n);

    ASSERT_EQ(n2.get_offset(), n.get_offset());
    ASSERT_EQ(n2.getString(), n.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceAsignation)
{
    const std::string s = "CTA";
    PseudoNucSequence n(s);
    PseudoNucSequence n2 = n;

    ASSERT_EQ(n2.get_offset(), n.get_offset());
    ASSERT_EQ(n2.getString(), n.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceCopyCtor)
{
    const std::string s = "CTA";
    PseudoNucSequence n(s);
    PseudoNucSequence n2(n);

    ASSERT_EQ(n2.get_offset(), n.get_offset());
    ASSERT_EQ(n2.getString(), n.getString());
}

TEST(GenericSequenceTest, NucSequenceSetTriplet)
{
    const std::string s = "CTA";
    NucSequence ns(s);
    ns.set_triplet(0, Triplet("atg"));

    ASSERT_EQ("AUG", ns.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceSetTriplet)
{
    const std::string s = "CTA";
    PseudoNucSequence pn(s);
    pn.set_triplet(0, PseudoTriplet("ykm"));

    ASSERT_EQ("YKM", pn.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceSetTripletTemplateParameter)
{
    const std::string s = "CTA";
    PseudoNucSequence pns(s);
    pns.set_triplet<Triplet> (0, Triplet("atg"));

    ASSERT_EQ("AUG", pns.getString());
}

TEST(GenericSequenceTest, NucSequenceEqual)
{
    NucSequence ns("CTA");
    NucSequence ns2("CTA");
    NucSequence ns3("ACTA");
    NucSequence ns4("CTA");
    ns3.set_offset(1);

    ASSERT_EQ(ns, ns2);
    ASSERT_EQ(ns3, ns4);
}

TEST(GenericSequenceTest, NucSequenceNotEqual)
{
    NucSequence ns("CTACT");
    NucSequence ns2("CT");
    NucSequence ns3("ATAAT");
    NucSequence ns4("AAT");
    ns3.set_offset(1);

    ASSERT_NE(ns, ns2);
    ASSERT_NE(ns3, ns4);
}

TEST(GenericSequenceTest, PseudoNucSequenceEqual)
{
    PseudoNucSequence ns("YKM");
    PseudoNucSequence ns2("YKM");
    PseudoNucSequence ns3("MKYKM");
    PseudoNucSequence ns4("KYKM");
    ns3.set_offset(2);
    ns4.set_offset(1);

    ASSERT_EQ(ns, ns2);
    ASSERT_EQ(ns3, ns4);
}

TEST(GenericSequenceTest, PseudoNucSequenceNotEqual)
{
    PseudoNucSequence n("YKM");
    PseudoNucSequence ns("YKMY");
    PseudoNucSequence ns2("MYKM");
    PseudoNucSequence ns3("KYM");
    ns3.set_offset(1);

    ASSERT_NE(n, ns);
    ASSERT_NE(ns2, ns3);
}

TEST(GenericSequenceTest, NucSequenceAdd)
{
    NucSequence n("CTG");
    n += Nucleotide::A;
    n += Nucleotide::G;

    ASSERT_EQ("CUGAG", n.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceAdd)
{
    PseudoNucSequence n("YKM");
    n += PseudoNucleotide::R;
    n += PseudoNucleotide::V;
    n += PseudoNucleotide::R;

    ASSERT_EQ("YKMRVR", n.getString());
}

TEST(GenericSequenceTest, NucSequenceOstream)
{
    NucSequence n("ACCC");
    std::ostringstream ostream;
    ostream << n;

    ASSERT_EQ("ACCC", ostream.str());
}

TEST(GenericSequenceTest, PseudoNucSequenceOstream)
{
    PseudoNucSequence pns("YKM");
    std::ostringstream ostream;
    ostream << pns;

    ASSERT_EQ("YKM", ostream.str());
}

TEST(GenericSequenceTest, PseudoNucSequenceFromNucSequence)
{
    NucSequence n("ACCC");
    PseudoNucSequence pns(n);
    PseudoNucSequence pns1("YKM");
    pns1 = n;

    ASSERT_EQ("ACCC", pns.getString());
    ASSERT_EQ("ACCC", pns1.getString());
}

TEST(GenericSequenceTest, NucSequenceFromPseudoNucSequence)
{
    NucSequence n;
    PseudoNucSequence pns("KMACCCA");
    pns.set_offset(2);
    pseudoNucSequence_to_nucSequence(pns, n);

    ASSERT_EQ(n.getString(), pns.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceSetOffset)
{
    PseudoNucSequence pns("YKMTTACT");
    pns.set_offset(1);

    ASSERT_EQ("KMUUACU", pns.getString());
    ASSERT_THROW(pns.set_offset(3), biopp::InvalidOffset);
}

TEST(GenericSequenceTest, NucSequenceSetOffset)
{
    NucSequence ns("ACATTTACT");
    ns.set_offset(2);

    ASSERT_EQ("AUUUACU", ns.getString());
    ASSERT_THROW(ns.set_offset(5), biopp::InvalidOffset);
}

TEST(GenericSequenceTest, NucSequenceComplement)
{
    NucSequence ns("ACATTTACT");
    NucSequence comp;
    ns.set_offset(2);
    ns.complement(comp);

    ASSERT_EQ("UAAAUGA", comp.getString());
}

TEST(GenericSequenceTest, NucSequenceReverseComplement)
{
    NucSequence ns("ACATTTACT");
    NucSequence comp;
    ns.set_offset(2);
    ns.reverseComplement(comp);

    ASSERT_EQ("AGUAAAU", comp.getString());
}

TEST(GenericSequenceTest, NucSequenceComplement_onsite)
{
    NucSequence ns("ACATTTACT");
    ns.set_offset(1);
    ns.complement();

    ASSERT_EQ("GUAAAUGA", ns.getString());
}

TEST(GenericSequenceTest, NucSequenceReverseComplement_onsite)
{
    NucSequence ns("ACATTTACT");
    NucSequence ns1("ACT");
    NucSequence ns2("CT");
    NucSequence ns3("T");
    ns.reverseComplement();
    ns1.reverseComplement();
    ns2.reverseComplement();
    ns3.reverseComplement();

    ASSERT_EQ("AGUAAAUGU", ns.getString());
    ASSERT_EQ("AGU", ns1.getString());
    ASSERT_EQ("AG", ns2.getString());
    ASSERT_EQ("A", ns3.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceComplement)
{
    PseudoNucSequence pns("ACATTTACT");
    PseudoNucSequence pns1("YKATMW");
    PseudoNucSequence comp;
    PseudoNucSequence comp1;
    pns.set_offset(2);
    pns.complement(comp);
    pns1.complement(comp1);

    ASSERT_EQ("UAAAUGA", comp.getString());
    ASSERT_EQ("RMUAKW", comp1.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceReverseComplement)
{
    PseudoNucSequence pns("ACATTTACT");
    PseudoNucSequence pns1("YKATMW");
    PseudoNucSequence comp;
    PseudoNucSequence comp1;
    pns.set_offset(2);
    pns.reverseComplement(comp);
    pns1.reverseComplement(comp1);

    ASSERT_EQ("AGUAAAU", comp.getString());
    ASSERT_EQ("WKAUMR", comp1.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceComplement_onsite)
{
    PseudoNucSequence pns("ACATTTACT");
    PseudoNucSequence pns1("YKATMW");
    pns.set_offset(1);
    pns.complement();
    pns1.complement();

    ASSERT_EQ("GUAAAUGA", pns.getString());
    ASSERT_EQ("RMUAKW", pns1.getString());
}

TEST(GenericSequenceTest, PseudoNucSequenceReverseComplement_onsite)
{
    PseudoNucSequence pns("ACATTTACT");
    PseudoNucSequence pns1("ACT");
    PseudoNucSequence pns2("CT");
    PseudoNucSequence pns3("T");
    PseudoNucSequence pns4("YKATMW");
    pns.reverseComplement();
    pns1.reverseComplement();
    pns2.reverseComplement();
    pns3.reverseComplement();
    pns4.reverseComplement();

    ASSERT_EQ("AGUAAAUGU", pns.getString());
    ASSERT_EQ("AGU", pns1.getString());
    ASSERT_EQ("AG", pns2.getString());
    ASSERT_EQ("A", pns3.getString());
    ASSERT_EQ("WKAUMR", pns4.getString());
}
